partial fix for broken automated tests
authorMatthieu Gallien <matthieu.gallien@nextcloud.com>
Wed, 29 Jan 2025 13:13:16 +0000 (14:13 +0100)
committerMatthieu Gallien <matthieu.gallien@nextcloud.com>
Fri, 7 Feb 2025 08:12:29 +0000 (09:12 +0100)
will use different validation method for hardware stored certificates
and pure software certificates emited by the nextcloud server

Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
src/libsync/clientsideencryption.cpp
src/libsync/clientsideencryption.h
src/libsync/foldermetadata.cpp
src/libsync/foldermetadata.h
src/libsync/updatee2eefolderusersmetadatajob.cpp
test/testclientsideencryptionv2.cpp

index 3f2a8a1d119dcd3e2036d3d47ccc3bcfd13c43fd..5aaa40bf5a9888f775f3effe3643cb12b9855a15 100644 (file)
@@ -937,7 +937,9 @@ const QString &ClientSideEncryption::getMnemonic() const
 
 void ClientSideEncryption::setCertificate(const QSslCertificate &certificate)
 {
-    _encryptionCertificate = CertificateInformation{_encryptionCertificate.getPrivateKeyData(), QSslCertificate{certificate}};
+    _encryptionCertificate = CertificateInformation{useTokenBasedEncryption() ? CertificateInformation::CertificateType::HardwareCertificate : CertificateInformation::CertificateType::SoftwareNextcloudCertificate,
+                                                    _encryptionCertificate.getPrivateKeyData(),
+                                                    QSslCertificate{certificate}};
 }
 
 const QSslCertificate& ClientSideEncryption::getCertificate() const
@@ -1411,7 +1413,9 @@ void ClientSideEncryption::publicCertificateFetched(Job *incoming)
         return;
     }
 
-    _encryptionCertificate = CertificateInformation{_encryptionCertificate.getPrivateKeyData(), QSslCertificate{readJob->binaryData(), QSsl::Pem}};
+    _encryptionCertificate = CertificateInformation{useTokenBasedEncryption() ? CertificateInformation::CertificateType::HardwareCertificate : CertificateInformation::CertificateType::SoftwareNextcloudCertificate,
+                                                    _encryptionCertificate.getPrivateKeyData(),
+                                                    QSslCertificate{readJob->binaryData(), QSsl::Pem}};
 
     if (_encryptionCertificate.getCertificate().isNull()) {
         fetchPublicKeyFromKeyChain(account);
@@ -2042,7 +2046,9 @@ void ClientSideEncryption::sendSignRequestCSR(const AccountPtr &account,
     connect(job, &SignPublicKeyApiJob::jsonReceived, job, [this, account, keyPair = std::move(keyPair)](const QJsonDocument& json, const int retCode) {
         if (retCode == 200) {
             const auto cert = json.object().value("ocs").toObject().value("data").toObject().value("public-key").toString();
-            _encryptionCertificate = CertificateInformation{_encryptionCertificate.getPrivateKeyData(), QSslCertificate{cert.toLocal8Bit(), QSsl::Pem}};
+            _encryptionCertificate = CertificateInformation{useTokenBasedEncryption() ? CertificateInformation::CertificateType::HardwareCertificate : CertificateInformation::CertificateType::SoftwareNextcloudCertificate,
+                                                            _encryptionCertificate.getPrivateKeyData(),
+                                                            QSslCertificate{cert.toLocal8Bit(), QSsl::Pem}};
             Bio certificateBio;
             const auto certificatePem = _encryptionCertificate.getCertificate().toPem();
             BIO_write(certificateBio, certificatePem.constData(), certificatePem.size());
@@ -2328,7 +2334,9 @@ void ClientSideEncryption::getPublicKeyFromServer(const AccountPtr &account)
     connect(job, &JsonApiJob::jsonReceived, [this, account](const QJsonDocument& doc, int retCode) {
         if (retCode == 200) {
             QString publicKey = doc.object()["ocs"].toObject()["data"].toObject()["public-keys"].toObject()[account->davUser()].toString();
-            _encryptionCertificate = CertificateInformation{_encryptionCertificate.getPrivateKeyData(), QSslCertificate{publicKey.toLocal8Bit(), QSsl::Pem}};
+            _encryptionCertificate = CertificateInformation{useTokenBasedEncryption() ? CertificateInformation::CertificateType::HardwareCertificate : CertificateInformation::CertificateType::SoftwareNextcloudCertificate,
+                                                            _encryptionCertificate.getPrivateKeyData(),
+                                                            QSslCertificate{publicKey.toLocal8Bit(), QSsl::Pem}};
             fetchAndValidatePublicKeyFromServer(account);
         } else if (retCode == 404) {
             qCDebug(lcCse()) << "No public key on the server";
@@ -3002,22 +3010,34 @@ CertificateInformation::CertificateInformation()
 
 CertificateInformation::CertificateInformation(PKCS11_KEY *hardwarePrivateKey,
                                                QSslCertificate &&certificate)
-    : _hardwarePrivateKey(hardwarePrivateKey)
-    , _certificate(std::move(certificate))
+    : _hardwarePrivateKey{hardwarePrivateKey}
+    , _certificate{std::move(certificate)}
+    , _certificateType{CertificateType::HardwareCertificate}
 {
     checkEncryptionCertificate();
 }
 
-CertificateInformation::CertificateInformation(const QByteArray &privateKey, QSslCertificate &&certificate)
+CertificateInformation::CertificateInformation(CertificateType certificateType,
+                                               const QByteArray &privateKey,
+                                               QSslCertificate &&certificate)
     : _hardwarePrivateKey()
     , _privateKeyData()
     , _certificate(std::move(certificate))
+    , _certificateType{certificateType}
 {
     if (!privateKey.isEmpty()) {
         setPrivateKeyData(privateKey);
     }
 
-    checkEncryptionCertificate();
+    switch (_certificateType)
+    {
+    case CertificateType::HardwareCertificate:
+        checkEncryptionCertificate();
+        break;
+    case CertificateType::SoftwareNextcloudCertificate:
+        doNotCheckEncryptionCertificate();
+        break;
+    }
 }
 
 bool CertificateInformation::operator==(const CertificateInformation &other) const
@@ -3208,4 +3228,12 @@ void CertificateInformation::checkEncryptionCertificate()
     }
 }
 
+void CertificateInformation::doNotCheckEncryptionCertificate()
+{
+    _certificateExpired = false;
+    _certificateNotYetValid = false;
+    _certificateRevoked = false;
+    _certificateInvalid = false;
+}
+
 }
index 0c09666898385786b2fa8ed25b5c3f88c76fed07..75bb149c9f6eb1a61efed80c708231b2e1976e41 100644 (file)
@@ -56,12 +56,18 @@ class ClientSideEncryption;
 
 class CertificateInformation {
 public:
+    enum class CertificateType {
+        SoftwareNextcloudCertificate,
+        HardwareCertificate,
+    };
+
     CertificateInformation();
 
     explicit CertificateInformation(PKCS11_KEY *hardwarePrivateKey,
                                     QSslCertificate &&certificate);
 
-    explicit CertificateInformation(const QByteArray& privateKey,
+    explicit CertificateInformation(CertificateType certificateType,
+                                    const QByteArray& privateKey,
                                     QSslCertificate &&certificate);
 
     [[nodiscard]] bool operator==(const CertificateInformation &other) const;
@@ -99,12 +105,16 @@ public:
 private:
     void checkEncryptionCertificate();
 
+    void doNotCheckEncryptionCertificate();
+
     PKCS11_KEY* _hardwarePrivateKey = nullptr;
 
     QByteArray _privateKeyData;
 
     QSslCertificate _certificate;
 
+    CertificateType _certificateType = CertificateType::SoftwareNextcloudCertificate;
+
     bool _certificateExpired = true;
 
     bool _certificateNotYetValid = true;
index fd4ed36ba5a87bc4c1672bc606a1e324835e9d35..8ceb22dd1ea8049984fb5d70455d1cc95f4a7a5d 100644 (file)
@@ -557,8 +557,12 @@ void FolderMetadata::initEmptyMetadata()
         return initEmptyMetadataLegacy();
     }
     qCDebug(lcCseMetadata()) << "Setting up empty metadata v2";
+
+    const auto certificateType = _account->e2e()->useTokenBasedEncryption() ?
+        FolderMetadata::CertificateType::HardwareCertificate : FolderMetadata::CertificateType::SoftwareNextcloudCertificate;
+
     if (_isRootEncryptedFolder) {
-        if (!addUser(_account->davUser(), _account->e2e()->getCertificate())) {
+        if (!addUser(_account->davUser(), _account->e2e()->getCertificate(), certificateType)) {
             qCDebug(lcCseMetadata) << "Empty metadata setup failed. Could not add first user.";
             _account->reportClientStatus(OCC::ClientStatusReportingStatus::E2EeError_GeneralError);
             return;
@@ -1043,7 +1047,9 @@ void FolderMetadata::slotRootE2eeFolderMetadataReceived(int statusCode, const QS
     initMetadata();
 }
 
-bool FolderMetadata::addUser(const QString &userId, const QSslCertificate &certificate)
+bool FolderMetadata::addUser(const QString &userId,
+                             const QSslCertificate &certificate,
+                             CertificateType certificateType)
 {
     Q_ASSERT(_isRootEncryptedFolder);
     Q_ASSERT(!certificate.isNull());
@@ -1052,9 +1058,23 @@ bool FolderMetadata::addUser(const QString &userId, const QSslCertificate &certi
         return false;
     }
 
-    const auto shareUserCertificate = CertificateInformation{{}, QSslCertificate{certificate}};
+    auto convertedCertificateType = CertificateInformation::CertificateType::HardwareCertificate;
+    switch (certificateType)
+    {
+    case CertificateType::HardwareCertificate:
+        convertedCertificateType = CertificateInformation::CertificateType::HardwareCertificate;
+        break;
+    case CertificateType::SoftwareNextcloudCertificate:
+        convertedCertificateType = CertificateInformation::CertificateType::SoftwareNextcloudCertificate;
+        break;
+    }
+
+    const auto shareUserCertificate = CertificateInformation{convertedCertificateType, {}, QSslCertificate{certificate}};
     if (userId.isEmpty() || certificate.isNull() || !shareUserCertificate.canEncrypt()) {
-        qCWarning(lcCseMetadata()) << "Could not add a folder user. Invalid userId or certificate.";
+        qCWarning(lcCseMetadata()) << "Could not add a folder user. Invalid userId or certificate."
+                                   << userId
+                                   << (certificate.isNull() ? "user certificate is invalid" : "user certificate is valid")
+                                   << (shareUserCertificate.canEncrypt() ? "certificate of share receiver user can encrypt" : "certificate of share receiver user cannot encrypt");
         return false;
     }
 
index 34fda88e86e544d4a658fbc7f473c300c2fc9954..0fee917710e782f4a3531957e693507c541a2c24 100644 (file)
@@ -93,6 +93,12 @@ public:
     };
     Q_ENUM(FolderType)
 
+    enum class CertificateType {
+        SoftwareNextcloudCertificate,
+        HardwareCertificate,
+    };
+    Q_ENUM(CertificateType)
+
     FolderMetadata(AccountPtr account, const QString &remoteFolderRoot, FolderType folderType = FolderType::Nested);
     /*
     * construct metadata based on RootEncryptedFolderInfo
@@ -121,7 +127,7 @@ public:
     [[nodiscard]] bool moveFromFileDropToFiles();
 
     // adds a user to have access to this folder (always generates new metadata key)
-    [[nodiscard]] bool addUser(const QString &userId, const QSslCertificate &certificate);
+    [[nodiscard]] bool addUser(const QString &userId, const QSslCertificate &certificate, CertificateType certificateType);
     // removes a user from this folder and removes and generates a new metadata key
     [[nodiscard]] bool removeUser(const QString &userId);
 
index c6bfc07c049b96faad4227c09cbf2768a39d836f..065ace9bc28f6928866a16a8a061d85e347bbfcb 100644 (file)
@@ -136,8 +136,11 @@ void UpdateE2eeFolderUsersMetadataJob::startUpdate()
             return;
         }
 
+        const auto certificateType = _account->e2e()->useTokenBasedEncryption() ?
+            FolderMetadata::CertificateType::HardwareCertificate : FolderMetadata::CertificateType::SoftwareNextcloudCertificate;
+
         const auto result = _operation == Operation::Add
-            ? _encryptedFolderMetadataHandler->folderMetadata()->addUser(_folderUserId, _folderUserCertificate)
+            ? _encryptedFolderMetadataHandler->folderMetadata()->addUser(_folderUserId, _folderUserCertificate, certificateType)
             : _encryptedFolderMetadataHandler->folderMetadata()->removeUser(_folderUserId);
 
         if (!result) {
index 96ef34ddb35590b4c16c505e09e558053063bcf5..30b98e09fb01d514c73f66ceec28ea1feca6d63b 100644 (file)
@@ -245,11 +245,11 @@ private slots:
         encryptedFile.initializationVector = EncryptionHelper::generateRandom(16);
         metadata->addEncryptedFile(encryptedFile);
 
-        QVERIFY(metadata->addUser(_secondAccount->davUser(), _secondAccount->e2e()->getCertificate()));
+        QVERIFY(metadata->addUser(_secondAccount->davUser(), _secondAccount->e2e()->getCertificate(), FolderMetadata::CertificateType::SoftwareNextcloudCertificate));
 
         QVERIFY(metadata->removeUser(_secondAccount->davUser()));
 
-        QVERIFY(metadata->addUser(_secondAccount->davUser(), _secondAccount->e2e()->getCertificate()));
+        QVERIFY(metadata->addUser(_secondAccount->davUser(), _secondAccount->e2e()->getCertificate(), FolderMetadata::CertificateType::SoftwareNextcloudCertificate));
 
         const auto encryptedMetadata = metadata->encryptedMetadata();
         QVERIFY(!encryptedMetadata.isEmpty());